package com.legendframework.core.dao.wrapper.defaults;

import com.legendframework.core.dao.SFunction;
import com.legendframework.core.dao.exception.DaoException;
import com.legendframework.core.dao.support.ColumnCache;
import com.legendframework.core.dao.support.LambdaUtils;
import com.legendframework.core.dao.support.SerializedLambda;
import com.legendframework.core.dao.utils.DaoStringUtils;
import com.legendframework.core.dao.wrapper.defaults.AbstractDefaultWrapper;

import java.util.Locale;
import java.util.Map;
import java.util.Optional;

public class LambdaQueryWrapper<T> extends AbstractDefaultWrapper<T, SFunction<T,?> , LambdaQueryWrapper<T>> {

    private Map<String, ColumnCache> columnMap = null;

    private boolean initColumnMap = false;


    /**
     * 不建议直接 new 该实例，使用 Wrappers.lambdaQuery()
     */
    public LambdaQueryWrapper() {
        this(null);
    }

    /**
     * 不建议直接 new 该实例，使用 Wrappers.lambdaQuery(entity)
     */
    public LambdaQueryWrapper(T entity){
        super.setEntity(entity);
        if (entity != null) {
            columnMap = LambdaUtils.getColumnMap(entity.getClass().getName());
            initColumnMap = true;
        }
    }

    private String getColumn(SerializedLambda lambda) {
        String fieldName = DaoStringUtils.resolveFieldName(lambda.getImplMethodName());
        if (!initColumnMap || !columnMap.containsKey(fieldName.toUpperCase(Locale.ENGLISH))) {
            String entityClassName = lambda.getImplClassName();
            columnMap = LambdaUtils.getColumnMap(entityClassName);
            assert columnMap == null || columnMap.isEmpty() : String.format("cannot find column's cache for \"%s\", so you cannot used \"%s\"!",entityClassName,this.getClass());
            initColumnMap = true;
        }
        return Optional.ofNullable(columnMap.get(fieldName.toUpperCase(Locale.ENGLISH)))
                .map(ColumnCache::getColumn)
                .orElseThrow(() -> new DaoException(String.format("your property named \"%s\" cannot find the corresponding database column name!", fieldName)));
    }

    @Override
    String getColumn(SFunction<T, ?> column) {
        if (column == null) {
            return null;
        }
        return getColumn(LambdaUtils.resolve(column));
    }

    @Override
    protected LambdaQueryWrapper<T> instance() {
        return new LambdaQueryWrapper<>(entity);
    }
}
